/**
 * @file blePro.c
 * @brief   
 * @author  xiaowine (xiaowine@sina.cn)
 * @version 01.00
 * @date    2021-04-07
 * 
 * @copyright Copyright (c) {2020}  xiaowine
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2021-04-07 <td>1.0     <td>wangh     <td>内容
 * </table>
 * ******************************************************************
 * *                   .::::
 * *                 .::::::::
 * *                ::::::::::
 * *             ..:::::::::::
 * *          '::::::::::::
 * *            .:::::::::
 * *       '::::::::::::::..        女神助攻,流量冲天
 * *            ..::::::::::::.     永不宕机,代码无bug
 * *          ``:::::::::::::::
 * *           ::::``:::::::::'        .:::
 * *          ::::'   ':::::'       .::::::::
 * *        .::::'      ::::     .:::::::'::::
 * *       .:::'       :::::  .:::::::::' ':::::
 * *      .::'        :::::.:::::::::'      ':::::
 * *     .::'         ::::::::::::::'         ``::::
 * * ...:::           ::::::::::::'              ``::
 * *```` ':.          ':::::::::'                  ::::.
 * *                   '.:::::'                    ':'````.
 * ******************************************************************
 */

/* Private includes ----------------------------------------------------------*/
#include "blePro.h"
#include "stm32f0xx_hal.h"
#include "user_data.h"
#include <string.h>
#include "appUser.h"
/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
volatile uint8_t rx_len = 0;        //接收一帧数据的长度
volatile uint8_t recv_end_flag = 0; //一帧数据接收完成标志
uint8_t txDMAbuffer[BUFFER_SIZE] = {0};
uint8_t rxDMAbuffer[BUFFER_SIZE] = {0};

uint8_t bleTxBuff[BUFFER_SIZE] = {0};
uint8_t bleRxBuff[BUFFER_SIZE] = {0};
uint8_t BleDataTemp[24] = {0};
uint8_t rxCount = 0;
uint8_t txCount = 0;
uint8_t rxStep = 0;

ble_cmd_t bleCmdType = BLE_PPP;
char bleAddr[30] = {0};
char bleName[30] = {0};

const cmd_map_st AT_command[17] = {
    {"+++", "AT+", "Mode=AT Mode"},                            // BLE_PPP
    {"AT+setBR 9600\r\n", "AT+", ""},                          // BLE_SETBR
    {"AT+getName\r\n", "AT+", ""},                             // BLE_GETNAME
    {"AT+setName=", "AT+", "restart effect!"},                 // BLE_SETNAME
    {"AT+getAddr\r\n", "AT+", ""},                             // BLE_GETADDR
    {"AT+setAddr=112233445566\r\n", "AT+", "restart effect!"}, // BLE_SETADDR
    {"AT+getStatus\r\n", "AT+", ""},                           // BLE_GETSTATUS
    {"AT+setAdvInt 80 100\r\n", "AT+", "restart effect!"},     // BLE_SETADVINT
    {"AT+setConnInt 36 24 23 00\r\n", "AT+", ""},              // BLE_SETCONNINT
    {"AT+disConnect\r\n", "AT+", ""},                          // BLE_DISCONNECT
    {"AT+reStart\r\n", "AT+", "restart now"},                  // BLE_RESTART
    {"AT+getPara\r\n", "AT+", ""},                             // BLE_GETPARA
    {"AT+exit\r\n", "AT+", "Mode=Normal"},                     // BLE_EXIT
    {"AT+shutDown\r\n", "AT+", "power off now!"},              // BLE_SHUTDOWN
    {"AT+reStore\r\n", "AT+", "restart now"},                  // BLE_RESTORE
    {"AT+getInfo\r\n", "AT+", ""},                             // BLE_GETINFO
    {"AT+help\r\n", "AT+", ""},                                // BLE_HELP
};

osEvent bleRxTxEvent;

extern UART_HandleTypeDef huart1;
extern DMA_HandleTypeDef hdma_usart1_rx;
extern osThreadId bleTid;
/* Private function prototypes -----------------------------------------------*/
void HAL_UART_DMAStopRX(UART_HandleTypeDef *huart);
static void rxProcess(void);
static void bleInitialization(void);
void pushCmdSendBuff(ble_cmd_t cmd, const char *Txdata);
/* Private user code ---------------------------------------------------------*/

void bleProc(void const *argument)
{
    HAL_UART_Receive_DMA(&huart1, rxDMAbuffer, BUFFER_SIZE);

    bleInitialization();

    while (1)
    {
        // rxProcess();
        // osDelay(10);
        bleRxTxEvent = osSignalWait(1, 10);
        if (bleRxTxEvent.status == osEventTimeout)
        {

            if ((regDataOk == 1) && ((GPIOA->IDR & GPIO_PIN_15) == GPIO_PIN_RESET))
            {
                regDataOk = 0;
                pushCmdSendBuff(BLE_TRANSMISSION, (void *)bleTxBuff);
            }
        }
        else
        {
            rxProcess();
        }
        if (((GPIOA->IDR & GPIO_PIN_15) == GPIO_PIN_RESET))
        {
            boardBLEFlag = 1;
        }
        else
        {
            boardBLEFlag = 0;
        }
    }
}

static void bleInitialization(void)
{
    static char step = 0;
    GPIOA->BSRR = GPIO_PIN_8;  //UART_SW
    GPIOA->BSRR = GPIO_PIN_11; //PWR_ON

    for (;;)
    {
        bleRxTxEvent = osSignalWait(1, 10);
        if (bleRxTxEvent.status == osEventTimeout)
        {
            switch (step)
            {
            case 0:
                osDelay(6000);
                step++;
                break;
            case 1:
                if (!commandMode)
                {
                    commandMode = 1;
                    commandOK = 0;
                    pushCmdSendBuff(BLE_PPP, 0);
                    step = 2;
                }
                break;
            case 2:
                if (commandOK)
                {
                    commandOK = 0;
                    pushCmdSendBuff(BLE_GETADDR, 0);
                    step = 3;
                }
                break;
            case 3:
                if (commandOK)
                {
                    commandOK = 0;
                    pushCmdSendBuff(BLE_GETNAME, 0);
                    step = 4;
                }
                break;
            case 4:
                if (commandOK)
                {
                    if (strncmp(bleName, bleAddr, 17))
                    {
                        commandOK = 0;
                        pushCmdSendBuff(BLE_SETNAME, bleAddr);
                        step = 5;
                    }
                    else
                    {
                        step = 7;
                    }
                }
                break;
            case 5:
                if (commandOK)
                {
                    commandOK = 0;
                    pushCmdSendBuff(BLE_RESTART, 0);
                    step = 6;
                }
                break;
            case 6:
                if (commandOK)
                {
                    step = 0;
                }
                break;
            case 7:
                if (commandOK)
                {
                    commandOK = 0;
                    pushCmdSendBuff(BLE_EXIT, 0);
                    step = 8;
                }
                break;
            case 8:
                if (commandOK)
                {
                    BLEInit = 1;
                    bleInitFlag = 1;
                    return;
                }
                break;
            default:
                break;
            }
        }
        else
        {
            rxProcess();
        }
    }
}

void pushCmdSendBuff(ble_cmd_t cmd, const char *Txdata)
{
    bleCmdType = cmd;
    memset(txDMAbuffer, 0, sizeof(txDMAbuffer));
    if (cmd == BLE_TRANSMISSION)
    {
        txCount = *(Txdata + 3) + 5;
        memcpy(txDMAbuffer, Txdata, txCount);
        HAL_UART_Transmit_DMA(&huart1, txDMAbuffer, txCount);
    }
    else
    {
        strcpy((char *)txDMAbuffer, AT_command[bleCmdType].cmd);
        if (Txdata)
        {
            strcat((char *)txDMAbuffer, Txdata);
            strcat((char *)txDMAbuffer, "\r\n");
        }
        HAL_UART_Transmit_DMA(&huart1, txDMAbuffer, strlen((const char *)txDMAbuffer));
    }
}

//串口接收空闲中断
void Usart1Receive_IDLE(UART_HandleTypeDef *huart)
{
    if (RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) //判断是否是空闲中断
    {
        uint8_t rx_len;
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);                            //清楚空闲中断标志（否则会一直不断进入中断）
        HAL_UART_DMAStop(&huart1);                                     //停止本次DMA传输
        rx_len = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //计算接收到的数据长度
        if (rx_len > 0)
        {
            if (rxCount + rx_len > BUFFER_SIZE)
                rxCount = 0;
            memcpy(bleRxBuff + rxCount, rxDMAbuffer, rx_len);
            rxCount += rx_len;
            uartGetflag = 1;
            osSignalSet(bleTid, 1);
        }
        memset(rxDMAbuffer, 0, rx_len);                          //清零接收缓冲区
        HAL_UART_Receive_DMA(&huart1, rxDMAbuffer, BUFFER_SIZE); //重新打开DMA接收
    }
}

void HAL_UART_DMAStopRX(UART_HandleTypeDef *huart)
{
    CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
    HAL_DMA_Abort(huart->hdmarx);
    CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
    CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    /* At end of Rx process, restore huart->RxState to Ready */
    huart->RxState = HAL_UART_STATE_READY;
}
// void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
// {
//     /* Prevent unused argument(s) compilation warning */
//     UNUSED(huart);

//     /* NOTE : This function should not be modified, when the callback is needed,
//             the HAL_UART_TxCpltCallback can be implemented in the user file.
//    */
// }
// void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
// {
//    /* Prevent unused argument(s) compilation warning */
//    UNUSED(huart);

//    /* NOTE : This function should not be modified, when the callback is needed,
//            the HAL_UART_RxCpltCallback can be implemented in the user file.
//   */
// }
// void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
// {
//   /* Prevent unused argument(s) compilation warning */
//   UNUSED(huart);

//   /* NOTE : This function should not be modified, when the callback is needed,
//             the HAL_UART_ErrorCallback can be implemented in the user file.
//    */
// }

static void rxProcess(void)
{
    if (uartGetflag)
    {
        uartGetflag = 0;
        if (commandMode)
        {
            if ((strstr((const char *)bleRxBuff, "\r\n")) || (rxCount >= 25))
            {
                uartRecOK = 1;
            }
        }
        else
        {
        again:
            if (rxStep == 0)
            {
                if (rxCount < 2)
                    goto rxContinue;
                if (memcmp(bleRxBuff, (void *)protocolHeader, 2) == 0)
                    rxStep = 1;
                else
                {
                    memcpy(bleRxBuff, bleRxBuff + 1, rxCount - 1);
                    rxCount--;
                    goto again;
                }
            }

            if (rxStep == 1)
            {
                if (rxCount < 4)
                    goto rxContinue;
                if (bleRxBuff[3] <= 15)
                    rxStep = 2;
                else
                {
                    memcpy(bleRxBuff, bleRxBuff + 2, rxCount - 2);
                    rxCount -= 2;
                    rxStep = 0;
                    goto again;
                }
            }

            if (rxStep == 2)
            {
                uint8_t checkSum, checkIndex;
                if (rxCount < bleRxBuff[3] + 5)
                    goto rxContinue;
                checkSum = getCheckSum(bleRxBuff);
                checkIndex = bleRxBuff[3] + 4;
                if (checkSum == bleRxBuff[checkIndex])
                {
                    uint8_t len = bleRxBuff[3] + 5;
                    memcpy(BleDataTemp, bleRxBuff, 20);
                    memcpy(bleRxBuff, bleRxBuff + len, rxCount - len);
                    rxCount -= len;
                    bleDataReday = 1;
                    // memset(bleRxBuff, 0, rxCount);
                    // rxCount = 0;
                    rxStep = 0;
                }
                else
                {
                    memcpy(bleRxBuff, bleRxBuff + 4, rxCount - 4);
                    rxCount -= 4;
                    rxStep = 0;
                    goto again;
                }
            }
        }
    }
rxContinue:
    if (uartRecOK)
    {
        char *atBak = strstr((const char *)bleRxBuff, "AT+ok");
        uartRecOK = 0;
        if (atBak)
        {
            switch (bleCmdType)
            {
            case BLE_PPP:
                if (strstr((const char *)bleRxBuff, "AT+"))
                {
                    commandOK = 1;
                }
                break;
            // case BLE_SETBR:                    break;
            case BLE_GETNAME:
                commandOK = 1;
                strncpy(bleName, atBak + strlen("AT+ok "), 20);
                break;
            case BLE_SETNAME:
                commandOK = 1;
                if (strstr((const char *)bleRxBuff, AT_command[bleCmdType].bkKey))
                {
                }
                break;
            case BLE_GETADDR:
                commandOK = 1;
                strncpy(bleAddr, atBak + strlen("AT+ok "), 20);
                break;
                // case BLE_GETSTATUS:                    break;
                // case BLE_SETADVINT:                    break;
                // case BLE_SETCONNINT:                    break;
                // case BLE_DISCONNECT:                    break;
            case BLE_RESTART:
                commandOK = 1;
                if (strstr((const char *)bleRxBuff, AT_command[bleCmdType].bkKey))
                {
                    commandMode = 0;
                }
                break;
                // case BLE_GETPARA: break;
            case BLE_EXIT:
                if (strstr((const char *)bleRxBuff, AT_command[bleCmdType].bkKey))
                {
                    commandMode = 0;
                }
                commandOK = 1;
                break;
            // case BLE_SHUTDOWN: break;
            // case BLE_RESTORE: break;
            // case BLE_GETINFO: break;
            // case BLE_HELP: break;
            default:
                commandOK = 1;
                break;
            }
        }
        else if (strstr((const char *)bleRxBuff, "AT+err"))
        {
            switch (bleCmdType)
            {
            case BLE_PPP:
                commandOK = 1;
                break;

            default:
                break;
            }
        }
        memset(bleRxBuff, 0, rxCount);
        rxCount = 0;
    }
}
uint8_t getCheckSum(uint8_t *Cache)
{
    uint8_t checkSum = 0;
    uint8_t i;
    for (i = 0; i < (*(Cache + 3) + 4); i++)
    {
        checkSum += *(Cache + i);
    }
    return checkSum;
}
